package org.filetransfer.file_transfer_java_backend.service;

import jakarta.persistence.criteria.Predicate;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.filetransfer.file_transfer_java_backend.entity.User;
import org.filetransfer.file_transfer_java_backend.model.*;
import org.filetransfer.file_transfer_java_backend.repository.UserRepository;
import org.filetransfer.file_transfer_java_backend.utils.JwtTokenUtil;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.time.Instant;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
@Service
@RequiredArgsConstructor
@Slf4j
@Transactional
public class UserService implements UserDetailsService {
      private final UserRepository userRepository;
    private final PasswordEncoder passwordEncoder;
    private final JwtTokenUtil jwtTokenUtil;
    
    @Override
    public UserDetails loadUserByUsername(String usernameOrEmail) throws UsernameNotFoundException {
        return userRepository.findByUsernameOrEmail(usernameOrEmail)
                .orElseThrow(() -> new UsernameNotFoundException("用户不存在: " + usernameOrEmail));
    }
    
    public AuthResponse register(UserRegistrationRequest request) {
        // Check if username or email already exists
        if (userRepository.existsByUsername(request.getUsername())) {
            throw new RuntimeException("用户名已存在");
        }
        if (userRepository.existsByEmail(request.getEmail())) {
            throw new RuntimeException("邮箱已存在");
        }
        
        // Create new user
        User user = User.builder()
                .username(request.getUsername())
                .email(request.getEmail())
                .password(passwordEncoder.encode(request.getPassword()))
                .displayName(request.getDisplayName() != null ? request.getDisplayName() : request.getUsername())
                .role(User.Role.USER)
                .enabled(true)
                .createdAt(Instant.now())
                .build();
        
        User savedUser = userRepository.save(user);
        log.info("新用户注册成功: {}", savedUser.getUsername());
          // Generate JWT token and refresh token
        String token = jwtTokenUtil.generateToken(savedUser);
        String refreshToken = jwtTokenUtil.generateRefreshToken(savedUser);
        
        return new AuthResponse(token, refreshToken, UserResponse.fromUser(savedUser));
    }
      public AuthResponse login(UserLoginRequest request) {
        // Find user by username or email
        User user = userRepository.findByUsernameOrEmail(request.getUsernameOrEmail())
                .orElseThrow(() -> new RuntimeException("用户不存在"));
        
        // Check if user is enabled
        if (!user.isEnabled()) {
            throw new RuntimeException("用户账户已被禁用");
        }
        
        // Verify password
        if (!passwordEncoder.matches(request.getPassword(), user.getPassword())) {
            throw new RuntimeException("密码错误");
        }        // Update last login time
        user.setLastLogin(Instant.now());
        userRepository.save(user);
        
        // Generate JWT token and refresh token
        String token = jwtTokenUtil.generateToken(user);
        String refreshToken = jwtTokenUtil.generateRefreshToken(user);
        
        log.info("用户登录成功: {}", user.getUsername());
        
        return new AuthResponse(token, refreshToken, UserResponse.fromUser(user));
    }
    
    @Transactional(readOnly = true)
    public UserResponse getCurrentUser(String username) {
        User user = userRepository.findByUsername(username)
                .orElseThrow(() -> new RuntimeException("用户不存在"));
        return UserResponse.fromUser(user);
    }
    
    public UserResponse updateUser(Long userId, UserUpdateRequest request, String currentUsername) {
        User currentUser = userRepository.findByUsername(currentUsername)
                .orElseThrow(() -> new RuntimeException("当前用户不存在"));
        
        User userToUpdate = userRepository.findById(userId)
                .orElseThrow(() -> new RuntimeException("用户不存在"));
        
        // Check permission: users can only update themselves, admins can update anyone
        if (!currentUser.getId().equals(userId) && currentUser.getRole() != User.Role.ADMIN) {
            throw new RuntimeException("没有权限修改此用户信息");
        }
        
        // Update fields
        if (request.getDisplayName() != null) {
            userToUpdate.setDisplayName(request.getDisplayName());
        }
        if (request.getEmail() != null) {
            // Check if email is already taken by another user
            Optional<User> existingUser = userRepository.findByEmail(request.getEmail());
            if (existingUser.isPresent() && !existingUser.get().getId().equals(userId)) {
                throw new RuntimeException("邮箱已被其他用户使用");
            }
            userToUpdate.setEmail(request.getEmail());
        }
        if (request.getAvatarUrl() != null) {
            userToUpdate.setAvatarUrl(request.getAvatarUrl());
        }
        
        // Only admin can change role
        if (request.getRole() != null && currentUser.getRole() == User.Role.ADMIN) {
            userToUpdate.setRole(request.getRole());
        }
        
        User updatedUser = userRepository.save(userToUpdate);
        log.info("用户信息更新成功: {}", updatedUser.getUsername());
        
        return UserResponse.fromUser(updatedUser);
    }
    
    public void changePassword(String username, ChangePasswordRequest request) {
        User user = userRepository.findByUsername(username)
                .orElseThrow(() -> new RuntimeException("用户不存在"));
        
        // Verify current password
        if (!passwordEncoder.matches(request.getCurrentPassword(), user.getPassword())) {
            throw new RuntimeException("当前密码不正确");
        }
        
        // Update password
        user.setPassword(passwordEncoder.encode(request.getNewPassword()));
        userRepository.save(user);
        
        log.info("用户密码修改成功: {}", user.getUsername());
    }

    @Transactional(readOnly = true)
    public Page<UserResponse> getAllUsers(
            Pageable pageable,
            String id,
            String name,
            Integer status,
            String remark,
            LocalDateTime startTime,
            LocalDateTime endTime
    ) {
        Specification<User> spec = (root, query, cb) -> {
            List<Predicate> predicates = new ArrayList<>();

            if (StringUtils.hasText(id)) {
                predicates.add(cb.equal(root.get("id"), id));
            }

            if (StringUtils.hasText(name)) {
                predicates.add(cb.or(
                        cb.like(root.get("username"), "%" + name + "%"),
                        cb.like(root.get("displayName"), "%" + name + "%")
                ));
            }

            if (status != null) {
                predicates.add(cb.equal(root.get("enabled"), status == 1));
            }

            if (StringUtils.hasText(remark)) {
                predicates.add(cb.like(root.get("email"), "%" + remark + "%"));
            }

            if (startTime != null) {
                predicates.add(cb.greaterThanOrEqualTo(root.get("createdAt"), startTime));
            }

            if (endTime != null) {
                predicates.add(cb.lessThanOrEqualTo(root.get("createdAt"), endTime));
            }

            return cb.and(predicates.toArray(new Predicate[0]));
        };

        return userRepository.findAll(spec, pageable)
                .map(UserResponse::fromUser);
    }


    @Transactional(readOnly = true)
    public UserResponse getUserById(Long userId) {
        User user = userRepository.findById(userId)
                .orElseThrow(() -> new RuntimeException("用户不存在"));
        return UserResponse.fromUser(user);
    }
    
    public void deleteUser(Long userId, String currentUsername) {
        User currentUser = userRepository.findByUsername(currentUsername)
                .orElseThrow(() -> new RuntimeException("当前用户不存在"));
        
        if (currentUser.getRole() != User.Role.ADMIN) {
            throw new RuntimeException("没有权限删除用户");
        }
        
        User userToDelete = userRepository.findById(userId)
                .orElseThrow(() -> new RuntimeException("用户不存在"));
        
        // Prevent admin from deleting themselves
        if (currentUser.getId().equals(userId)) {
            throw new RuntimeException("不能删除自己的账户");
        }
        
        userRepository.delete(userToDelete);
        log.info("用户删除成功: {}", userToDelete.getUsername());
    }
    
    public void toggleUserStatus(Long userId, String currentUsername) {
        User currentUser = userRepository.findByUsername(currentUsername)
                .orElseThrow(() -> new RuntimeException("当前用户不存在"));
        
        if (currentUser.getRole() != User.Role.ADMIN) {
            throw new RuntimeException("没有权限修改用户状态");
        }
        
        User userToToggle = userRepository.findById(userId)
                .orElseThrow(() -> new RuntimeException("用户不存在"));
        
        // Prevent admin from disabling themselves
        if (currentUser.getId().equals(userId)) {
            throw new RuntimeException("不能修改自己的账户状态");
        }
        
        userToToggle.setEnabled(!userToToggle.getEnabled());
        userRepository.save(userToToggle);
        
        log.info("用户状态修改成功: {} -> {}", userToToggle.getUsername(), userToToggle.getEnabled());
    }
    
    public AuthResponse refreshToken(RefreshTokenRequest request) {
        String refreshToken = request.getRefreshToken();
        
        // Validate refresh token
        if (!jwtTokenUtil.validateRefreshToken(refreshToken)) {
            throw new RuntimeException("无效的刷新令牌");
        }
        
        // Extract username from refresh token
        String username = jwtTokenUtil.getUsernameFromToken(refreshToken);
        
        // Find user
        User user = userRepository.findByUsername(username)
                .orElseThrow(() -> new RuntimeException("用户不存在"));
        
        // Check if user is still enabled
        if (!user.isEnabled()) {
            throw new RuntimeException("用户账户已被禁用");
        }
        
        // Generate new tokens
        String newToken = jwtTokenUtil.generateToken(user);
        String newRefreshToken = jwtTokenUtil.generateRefreshToken(user);
        
        log.info("Token刷新成功: {}", user.getUsername());
        
        return new AuthResponse(newToken, newRefreshToken, UserResponse.fromUser(user));
    }
    
    public void logout(RefreshTokenRequest request) {
        String refreshToken = request.getRefreshToken();
        
        // Validate refresh token format
        if (!jwtTokenUtil.validateRefreshToken(refreshToken)) {
            throw new RuntimeException("无效的刷新令牌");
        }
        
        // Extract username from refresh token for logging
        String username = jwtTokenUtil.getUsernameFromToken(refreshToken);
        
        // Revoke the refresh token by adding it to blacklist
        jwtTokenUtil.revokeRefreshToken(refreshToken);
        
        log.info("用户登出成功: {}", username);
    }
}
